package com.hz.pay.center.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.hz.pay.center.config.MqConfig;
import com.hz.pay.center.config.PayCenterConfig;
import com.pay.common.enums.PayStatusEnum;
import com.hz.pay.center.model.NoticeResultInfo;
import com.hz.pay.center.model.PaySerialInfo;
import com.hz.pay.center.service.INoticeResultService;
import com.hz.pay.center.service.INoticeRuleService;
import com.hz.pay.center.service.IPayNotifyService;
import com.hz.pay.center.service.IPaySerialService;
import com.pay.common.utils.PayDigestUtil;
import com.hz.pay.center.vo.MyMessagePostProcessor;
import com.pay.common.resp.PayNotifyData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * 支付回调业务处理
 */
@Service
public class PayNotifyServiceImpl implements IPayNotifyService {


    @Autowired
    private PayCenterConfig payCenterConfig;

    @Autowired
    private IPaySerialService paySerialService;

    @Autowired
    private RestTemplate restTemplate;


    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    private Logger logger = LoggerFactory.getLogger(PayNotifyServiceImpl.class);


    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private INoticeResultService noticeResultService;


    @Autowired
    private INoticeRuleService noticeRuleService;

    @Override
    public String notify(Map<String, String> map) {

        String outTradeNo  =  map.get("out_trade_no");

        //2.进行验证签名， 验证请求是支付宝发出来。
        try {
            boolean flag  = AlipaySignature.rsaCheckV1(map,payCenterConfig.getAlipayPubKey(),"utf-8",payCenterConfig.getSignType());

            if (!flag){
                logger.info("支付流水号：{},验证签名失败",outTradeNo);
                return "fail";
            }

        } catch (AlipayApiException e) {
            logger.error("AlipayApiException ：" + outTradeNo,e);
            return "fail";

        }

        //支付流水
       PaySerialInfo paySerialInfo =  paySerialService.queryByPaySerialNo(outTradeNo);
        //3.商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号
        if (ObjectUtils.isEmpty(paySerialInfo)){
            logger.info("支付流水号：{},不存在数据库中",outTradeNo);
            return "fail";
        }


        BigDecimal totalAmt = new BigDecimal(map.get("total_amount"));

        //4. 判断 total_amount 是否确实为该订单的实际金额（即商户订单创建时的金额）
        //  100.00            100

//
//        totalAmt.compareTo()

        if (totalAmt.compareTo(paySerialInfo.getPayAmount())!= 0){

            logger.info("支付流水号：{},回调金额:{}和支付金额:{}不匹配",outTradeNo,totalAmt,paySerialInfo.getPayAmount());

            return "fail";
        }

//
//        request.getParameter("seller_id");
//        request.getParameter("seller_email");

        //5.验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商户可能有多个 seller_id/seller_email）；



//        request.getParameter("app_id");

        //6.验证 app_id 是否为该商户本身。



        //更新支付流水的状态

        String tradeStatus = map.get("trade_status");//request.getParameter("trade_status");
        String paySuccessTime = map.get("gmt_payment");

        PaySerialInfo record = new PaySerialInfo();


        //封装回调参数
        PayNotifyData payNotifyData = new PayNotifyData();

        if ("TRADE_FINISHED".equals(tradeStatus) ||"TRADE_SUCCESS".equals(tradeStatus) ){
            //更新支付流水成功
            //update tb_pay_serials set pay_status pay_desc pay_success_time gmt_payment update_time where

//            PayStatusEnum.PAU_SUCCESS;

            //yyyy-MM-dd HH:mm:ss

            String bankRespNo = map.get("trade_no");


            record.setId(paySerialInfo.getId());
            record.setPayStatus(PayStatusEnum.PAU_SUCCESS.getCode());
            record.setPayDesc(PayStatusEnum.PAU_SUCCESS.getMsg());
            record.setBankRespNo(bankRespNo);

            record.setUpdateTime( new Date());

            try {
                record.setPaySuccessTime(simpleDateFormat.parse(paySuccessTime));
            } catch (ParseException e) {
                e.printStackTrace();
            }

            paySerialService.updateTrade(record);


            //回调
            payNotifyData.setTradeStatus(PayStatusEnum.PAU_SUCCESS.getCode());
            payNotifyData.setStatusDesc(PayStatusEnum.PAU_SUCCESS.getMsg());



        } else if("WAIT_BUYER_PAY".equals(tradeStatus)){

            //update tb_pay_serials set pay_status pay_desc pay_success_time bank_resp_no update_time where
            record.setId(paySerialInfo.getId());
            record.setPayStatus(PayStatusEnum.PAYING.getCode());
            record.setPayDesc(PayStatusEnum.PAYING.getMsg());

            paySerialService.updateTrade(record);

            //回调
            payNotifyData.setTradeStatus(PayStatusEnum.PAU_SUCCESS.getCode());
            payNotifyData.setStatusDesc(PayStatusEnum.PAU_SUCCESS.getMsg());
            try {
                payNotifyData.setPaySuccessTime(simpleDateFormat.parse(paySuccessTime));
            } catch (ParseException e) {
                e.printStackTrace();
            }


            //更新为支付中
        } else if("TRADE_CLOSED".equals(tradeStatus)){
            //update tb_pay_serials set pay_status pay_desc pay_success_time bank_resp_no update_time where

            record.setId(paySerialInfo.getId());
            record.setPayStatus(PayStatusEnum.PAY_FAIL.getCode());
            record.setPayDesc(PayStatusEnum.PAY_FAIL.getMsg());


            paySerialService.updateTrade(record);

            //回调
            payNotifyData.setTradeStatus(PayStatusEnum.PAU_SUCCESS.getCode());
            payNotifyData.setStatusDesc(PayStatusEnum.PAU_SUCCESS.getMsg());


            //更新交易失败
        }else {
            //TODO 抛出异常
        }

        //通知订单系统支付结果
        String url = "http://127.0.0.1:8084/orderPay/notify"; //TODO

        //封装通知业务的回调参数
        payNotifyData.setMchId(paySerialInfo.getMchId());
        payNotifyData.setOrderId(paySerialInfo.getOrderId());
        payNotifyData.setPayChannel(paySerialInfo.getPayChannel());
        payNotifyData.setPayWay(paySerialInfo.getPayWay());
        payNotifyData.setPasySerialNo(paySerialInfo.getPaySerialNo());

        JSONObject jsonObject  = null;
        try {
            //生成签名
             jsonObject  = (JSONObject) JSON.toJSON(payNotifyData);
            String sign = PayDigestUtil.generateSignature(jsonObject,"test123","MD5");
            payNotifyData.setSign(sign);
            payNotifyData.setSignType("MD5");
        } catch (Exception e) {
           logger.error("Exception",e);
           return "fail";
        }

        //查询流水号是否存在通知
        NoticeResultInfo noticeResultInfo = noticeResultService.queryByPaySerialNo(paySerialInfo.getPaySerialNo());

        //第一次通知
        if (ObjectUtils.isEmpty(noticeResultInfo)){

            //{code : 0 } success
            String rlt = restTemplate.postForObject(url,payNotifyData,String.class);

            //确保通知到 业务系统
            if (!"success".equals(rlt)){
                long time = noticeRuleService.getTime(paySerialInfo.getMchId(),1);

                // 5分钟后通知。  用延迟队列
                // 交换机       路由key       请求对象

//                MessageProperties messageProperties = new MessageProperties();
//                messageProperties.setExpiration("20000"); // 设置过期时间，单位：毫秒
//
////                JSONObject jsonObject = new JSONObject();
//
//
//                byte[] msgBytes = jsonObject.toJSONString().getBytes();        ;//"测试消息自动过期".getBytes();
//                Message message = new Message(msgBytes, messageProperties);

                // 设置每条消息的过期时间
                MyMessagePostProcessor myMessagePostProcessor = new MyMessagePostProcessor(time);

                rabbitTemplate.convertAndSend(MqConfig.PAY_NOTIFY_TOPIC_EXCHANGE,"pay.notify",payNotifyData,myMessagePostProcessor);


                // 创建失败的通知

                NoticeResultInfo resultInfo = new NoticeResultInfo();

                resultInfo.setMchId(paySerialInfo.getMchId());
                resultInfo.setNoticeCount(1); //TODO
                resultInfo.setPaySerialNo(paySerialInfo.getPaySerialNo());
                resultInfo.setNoticeStatus("1"); //TODO
                resultInfo.setCreateTime(new Date());


                noticeResultService.createNoticeResult(resultInfo);

            }else{
                //创建成功的通知
                NoticeResultInfo resultInfo = new NoticeResultInfo();

                resultInfo.setMchId(paySerialInfo.getMchId());
                resultInfo.setNoticeCount(1); //TODO
                resultInfo.setPaySerialNo(paySerialInfo.getPaySerialNo());
                resultInfo.setNoticeStatus("0"); //TODO

                Date nowDate = new Date();
                resultInfo.setCreateTime(nowDate);
                resultInfo.setSuccessTime(nowDate);

                noticeResultService.createNoticeResult(resultInfo);
            }




            return "success";
        }

        // 判断通知状态 是否终太 失败/成功
        if ("-1".equals(noticeResultInfo.getNoticeStatus()) || "0".equals(noticeResultInfo.getNoticeStatus()) ){

            // 通知已经成功或者失败
            return "success";
        }

        //判断通知次数是否达到最多的次数
        if (5 >= noticeResultInfo.getNoticeCount()){
            //通知次数达到上限
            return "success";
        }

        int noticeCount = noticeResultInfo.getNoticeCount();


        long time = noticeRuleService.getTime(paySerialInfo.getMchId(),noticeCount);

        MyMessagePostProcessor myMessagePostProcessor = new MyMessagePostProcessor(time);

        rabbitTemplate.convertAndSend(MqConfig.PAY_NOTIFY_TOPIC_EXCHANGE,"pay.notify",payNotifyData,myMessagePostProcessor);


        return "success";

    }

    public static void main(String[] args) {
        BigDecimal b1 = new BigDecimal("100");
        BigDecimal b2 = new BigDecimal("101");

        System.out.println(b1.compareTo(b2));


    }
}
